`timescale 1ns/100ps

`include "sim_glb.sv"
`include "public_head.sv"

module tc;

localparam          CLK_PRD                 = 5;
localparam          MAX_LEN                 = 100;

reg                                         rst_n;
reg                                         clk;


initial begin:CRG
    rst_n=1'b0;
    clk=1'b0;

    fork
        rst_n=#100.5 1'b1;
        forever clk=#CLK_PRD ~clk;
    join
end

RGRS_MNG    rgrs;
initial begin:REGRESS
    rgrs = new("tc_dbg", 2);

    rgrs.wait_chks_done(100_000_000);
end

vld_rdy_src_it #(9, 2, MAX_LEN) a2b_cmd_src(clk);
vld_rdy_dst_it #(9, 2, MAX_LEN) a2b_cmd_dst(clk);
assign a2b_cmd_dst.vld  = a2b_cmd_src.vld;
assign a2b_cmd_dst.sop  = a2b_cmd_src.sop;
assign a2b_cmd_dst.eop  = a2b_cmd_src.eop;
assign a2b_cmd_dst.info = a2b_cmd_src.info;
assign a2b_cmd_dst.data = a2b_cmd_src.data;
assign a2b_cmd_src.rdy  = a2b_cmd_dst.rdy;

initial begin:SRC
    logic [9-1:0] data[MAX_LEN-1:0];

    data[0] = 9'h1d1;
    data[1] = 9'h1d2;
    data[2] = 9'h1d3;
    data[3] = 9'h1d4;
    data[4] = 9'h1d5;
    data[5] = 9'h1d6;
    data[6] = 9'h1d7;
    data[7] = 9'h1d8;
    
    $display("$clog2(0)=%d", $clog2(0));
    $display("$clog2(1)=%d", $clog2(1));
    $display("$clog2(2)=%d", $clog2(2));
    $display("$clog2(3)=%d", $clog2(3));
    $display("$clog2(4)=%d", $clog2(4));
    $display("$clog2(5)=%d", $clog2(5));
    @(posedge rst_n);
    a2b_cmd_src.src_tx_t(1, 4, 2'd1, data);
    a2b_cmd_src.src_tx_t(0, 8, 2'd3, data);

    rgrs.one_chk_done("SRC is done.");
end


initial begin:DST
    integer     len;
    logic [1:0] info;
    logic [8:0] data[MAX_LEN-1:0];

    @(posedge rst_n);
    
    a2b_cmd_dst.dst_rx_t(50, len, info, data);
    a2b_cmd_dst.dst_rx_t(50, len, info, data);

    rgrs.one_chk_done("DST is done.");
end

req_ack_src_it #(12+16, 16) mpi_src(clk);
req_ack_dst_it #(12+16, 16) mpi_dst(clk);

assign mpi_dst.req  = mpi_src.req;
assign mpi_dst.nfr  = mpi_src.nfr;
assign mpi_dst.info = mpi_src.info;
assign mpi_src.ack  = mpi_dst.ack;
assign mpi_src.resp = mpi_dst.resp;

initial begin:REQ
    logic [11:0]    addr;
    logic [15:0]    wdata;
    logic           ren;

    @(posedge rst_n);
    
    {addr, wdata, ren} = {12'h0a0, 16'hd000, 1'b0}; 
    mpi_src.src_req_t(1, ren, {addr, wdata});

    {addr, wdata, ren} = {12'h0b0, 16'hd100, 1'b0}; 
    mpi_src.src_req_t(10, ren, {addr, wdata});

    {addr, wdata, ren} = {12'h0a0, 16'haaaa, 1'b1}; 
    mpi_src.src_req_t(0, ren, {addr, wdata});
end

initial begin:ACK
    logic [11:0]    addr;
    logic [15:0]    data;
    logic           ren;

    @(posedge rst_n);
    
    mpi_dst.info_rx_t(ren, {addr, data});
    mpi_dst.dst_ack_t(((ren) ? 10 : 1), data);

    mpi_dst.info_rx_t(ren, {addr, data});
    mpi_dst.dst_ack_t(((ren) ? 10 : 1), data);

    mpi_dst.info_rx_t(ren, {addr, data});
    mpi_dst.dst_ack_t(((ren) ? 10 : 1), data);
end

lpsg_prbs #(      // low-pass signal generator by means of PRBS
        .LPSG_DW                        (12                             ),
        .PRBS_N                         (23                             ),
        .EMA_K_MAX                      (7                              ),	// Maximum of cfg_ema_k
        .EMA_K_MIN                      (2                              ),	// Minimum of cfg_ema_k
        .GAIN_DW                        (8                              ),	// total bit-width
        .GAIN_FW                        (5                              ) 	// fractional bit-width
) u_lpsg ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .lpsg_dat                       (                               ),

        .cfg_ema_k                      (3'd3                           ),
        .cfg_gain                       ({3'd1, 5'd0}                   )	// u(GAIN_DW, GAIN_FW)
);

reg locked;

initial begin
    locked = 1'b0;

    @(posedge rst_n);
    repeat(180) begin
        @(posedge clk);
    end
    locked = 1'b1;
    #10_000;

    repeat(4) begin
        @(posedge clk);
        locked = 1'b0;
        @(posedge clk);
        locked = 1'b1;
        @(posedge clk);
    end
end

watch_dog #(
        .TIME_UNIT_SELF                 (1'b1                           ),	// 1'b0:use external time_unit_i; 1'b1:generate time_unit internal;
        .TU_PERIOD                      (8                              ),	// unused if TIME_UNIT_SELF==1'b0, else must TU_PERIOD = 2^N
        .FAIL_LEVEL                     (1'b0                           ),	// if 'watch_level'==FAIL_LEVEL, means fail event is watched
        .LEVEL_TU                       (10                             ),	// if fail level in 'watch_level' is watched for a long time(LEVEL_TU*TU_PERIOD), request reset
        .FAIL_EDGE                      (1'b0                           ),	// 1'b0:falling edge means fail event is watched; 1'b1:rising edge
        .EDGE_NUM                       (4                              ),	// if enough times of fail edge in 'watch_edge' is watched, request reset
        .RST_ACT_LEVEL                  (1'b1                           ),	// gen_reset active 1'b0:low; 1'b1:high;
        .RST_ACT_NUM                    (3                              ),	// clock number of gen_reset active
        .RST_GAP_TU                     (10                             )	// minimus gap(RST_GAP_TU*TU_PERIOD) between 2 gen_reset active
) u_watch_dog ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),

// periodical pulse with longer period
        .time_unit_i                    (                               ),	// unused if TIME_UNIT_SELF
        .time_unit_o                    (                               ),	// cascade out

        .watch_level                    (locked                         ),
        .watch_edge                     (locked                         ),

        .gen_reset                      (                               )
);

endmodule

